;; The first four lines of this file were added by Dracula.
;; They tell DrScheme that this is a Dracula Modular ACL2 program.
;; Leave these lines unchanged so that DrScheme can properly load this file.
#reader(planet "reader.rkt" ("cce" "dracula.plt") "modular" "lang")
(require "icrop.lisp")

(require "iimage.lisp")

(require "icommon.lisp")


(module MCrop
  (include-book "list-utilities" :dir :teachpacks)
  (include-book "avl-rational-keys" :dir :teachpacks)
  (import IImage)
  (import ICommon)


 ; cuts of the end, starting with and including from and including until
  (defun cut-col (tree from until)
    (if (equal from (+ until 1))
        tree
        (cut-col (avl-delete tree from)
                    (+ from 1)
                    until))
    )
  
  ; shifts pixels in the row to the left by from
  ; takes a tree, the first and last pixel to be included, and i starting at from
  (defun shift-col (tree from until i)
    (if (equal i (+ until 1)) ; if we have passed the last col to be included, return the tree
        tree
        (shift-col (avl-insert tree (+ (- i from) 1) (cdr (avl-retrieve tree i)))
                  from until (+ i 1))))
  
   ; goes through all the rows and shifts and cuts them
  (defun process-row (tree from until width)
    (cut-col (shift-col tree from until from)
         (+ (- until from) 2) width))
  
  ; cuts of rown at the bottom, starting at from going until the end of the image
  (defun cut-row (tree from until)
    (if (equal from (+ until 1))
        tree
        (cut-row (avl-delete tree from)
                    (+ from 1)
                    until))
    )
  
  ; shifts up or sideways rown in the tree, operates on y1 to y2 moving them by y1
  (defun shift-row (tree from until i x1 x2 width)
    (if (equal i (+ until 1)) ; if we have passed the last row to be included, return the tree
        tree
        (shift-row (avl-insert tree (+ (- i from) 1)
                           (process-row (cdr (avl-retrieve tree i))
                                        x1 x2 width))
                  from until (+ i 1) x1 x2 width)))
 
  ; internal crop function
  (defun crop-int (tree x1 y1 x2 y2 width height)
    (cut-row (shift-row tree y1 y2 y1 x1 x2 width) ; start at y1 + 1
                (+ (- y2 y1) 2) height)
    )
  
  ; public accessible crop function, takes in the tree, parses args
  ; also takes care of errors in the args
  (defun MainCrop (tree args)
    (cond
      ((null tree)                                           (mv tree (list "Error: empty image specified")))
      ((not (equal (len args) 4))                            (mv tree (list "Wrong number of arguments, expected 4 arguments (two points)")))
      ((not (validPair (car args) (cadr args) (caddr args) (cadddr args) (getWidth tree) (getHeight tree)))
           (list tree (list "Arguments do not constitute a valid pixel pair. Please enter 4 numbers as x1 y1 x2 y2")))
      (t                                                 
        (mv (let* ((width (getWidth tree))
           (height (getHeight tree))
           (x1 (car args))
           (y1 (cadr args));(+ (- width (cadr args)) 1))
           (x2 (caddr args))
           (y2 (cadddr args)));(+ (- width (cadddr args)) 1)))
      ;; add error checking here, maybe flip y cords
      (crop-int (setHeight (setWidth tree (+ (- x2 x1) 1)) (+ (- y2 y1) 1)) ; store new width and height in tree
                            x1 y1 x2 y2 width height)) (list "Successfully cropped image.")))))
       
      
           
  
  
    (export ICrop))